#include "stdafx.h"
#include "FileMemoryMapping.h"

CFileMemoryMapping::CFileMemoryMapping()  
{
    // Set member vars to the default values
    m_hFile = INVALID_HANDLE_VALUE;
    m_uFileLength = 0;
    m_hFileMapping = NULL;  

    SYSTEM_INFO si;  
    GetSystemInfo(&si);
    m_dwAllocGranularity = si.dwAllocationGranularity;  
}

CFileMemoryMapping::~CFileMemoryMapping()
{
    Destroy();
}


BOOL CFileMemoryMapping::Init(LPCTSTR szFileName)
{
    if(m_hFile!=INVALID_HANDLE_VALUE)
    {
        // If a file mapping already created, destroy it
        Destroy();    
    }

    // Open file handle
    m_hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    if(m_hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    // Create file mapping
    m_hFileMapping = CreateFileMapping(m_hFile, 0, PAGE_READONLY, 0, 0, 0);
    LARGE_INTEGER size;
    GetFileSizeEx(m_hFile, &size);	
    m_uFileLength = size.QuadPart; 

    return TRUE;
}

BOOL CFileMemoryMapping::Destroy()
{
    // Unmap all views
    std::map<DWORD, LPBYTE>::iterator it;
    for(it=m_aViewStartPtrs.begin(); it!=m_aViewStartPtrs.end(); it++)
    {
        if(it->second != NULL)
            UnmapViewOfFile(it->second);    
    }
    m_aViewStartPtrs.clear();

    // Close file mapping handle
    if(m_hFileMapping!=NULL)
    {
        CloseHandle(m_hFileMapping);    
    }

    // Close file handle
    if(m_hFile!=INVALID_HANDLE_VALUE)
    {
        CloseHandle(m_hFile);    
    }

    m_hFileMapping = NULL;
    m_hFile = INVALID_HANDLE_VALUE;		
    m_uFileLength = 0;  

    return TRUE;
}

ULONG64 CFileMemoryMapping::GetSize()
{
    return m_uFileLength;
}

LPBYTE CFileMemoryMapping::CreateView(DWORD dwOffset, DWORD dwLength)
{
    DWORD dwThreadId = GetCurrentThreadId();
    DWORD dwBaseOffs = dwOffset-dwOffset%m_dwAllocGranularity;
    DWORD dwDiff = dwOffset-dwBaseOffs;
    LPBYTE pPtr = NULL;

    CAutoLock lock(&m_csLock);

    std::map<DWORD, LPBYTE>::iterator it = m_aViewStartPtrs.find(dwThreadId);
    if(it!=m_aViewStartPtrs.end())
    {
        UnmapViewOfFile(it->second);
    }

    pPtr = (LPBYTE)MapViewOfFile(m_hFileMapping, FILE_MAP_READ, 0, dwBaseOffs, dwLength+dwDiff);
    if(it!=m_aViewStartPtrs.end())
    {
        it->second = pPtr;
    }
    else
    {
        m_aViewStartPtrs[dwThreadId] = pPtr;
    }

    return (pPtr+dwDiff);
}